package gui;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;

import javax.swing.ImageIcon;
import util.Molecule;

import com.wolfram.alpha.WAEngine;
import com.wolfram.alpha.WAException;
import com.wolfram.alpha.WAImage;
import com.wolfram.alpha.WAPod;
import com.wolfram.alpha.WAQuery;
import com.wolfram.alpha.WAQueryResult;
import com.wolfram.alpha.WASubpod;


/**
 * @author Donald Scott
 * @since 4/7/11 
 * 
 * Dependencies:
 *     commons-codec-1.3.jar
 *     httpclient-4.0.1.jar
 *     httpcore-4.0.1.jar
 *     commons-logging.jar
 */

public class MoleculeImageCenter {

    final private static String appid = "PPU9X9-8943YQYY82";
    
    private static HashMap<String,ImageIcon> images;
    
    public MoleculeImageCenter(){
    	images = loadCache();
    }
    
    @SuppressWarnings("unchecked")
	private static HashMap<String, ImageIcon> loadCache() {
    	HashMap<String,ImageIcon> images = null;
    	
		try{
    		FileInputStream fis = null;
	        try {
	        	fis = new FileInputStream("trunk//gui//image_cache.cache");
	        } catch (Exception e) {
	        	fis = new FileInputStream("src//gui//image_cache.cache");
	        }   
	        
	        ObjectInputStream in = null;
	        in = new ObjectInputStream(fis);
	        images = (HashMap<String, ImageIcon>) in.readObject();
	        in.close();
	        System.out.println("Cache loaded");
	        
    	}catch(Exception e){
    		MoleculeImageCenter.images = new HashMap<String,ImageIcon>();
    		saveCache();
    	}
    	if (images == null)
    		images = new HashMap<String, ImageIcon>();
    	return images;
	}
    private static void saveCache(){
    	try{
    		FileOutputStream fos = null;

	        try 
	        {
	        	fos = new FileOutputStream("trunk//gui//image_cache.cache");
	        } catch (Exception e) {
	        	fos = new FileOutputStream("src//gui//image_cache.cache");
	        }
			
			ObjectOutputStream out = null;
			try
			{
				out = new ObjectOutputStream(fos);
				out.writeObject(images);
				out.close();
			}
			catch(IOException ex)
			{
				ex.printStackTrace();
			}
    	}catch(Exception e){   
        	System.err.println("Failed to create file.");
        }
    }
    /**
     * Worker thread to facilitate image retrieval.  
     * @author Donald Scott
     * @since 4/8/11
     */
    private static class LookupWorker implements Runnable{
    	Molecule molecule;
    	StoiPanel panel;
    	public LookupWorker(StoiPanel panel,Molecule molecule){
    		this.molecule = molecule;
    		this.panel = panel;
    	}
    	
		@Override
		public void run() {
			ImageIcon image = null;
			URL url = lookupImageURL(molecule);
			images.put(molecule.toString(),image);//add if null of not.  If null it will cause it to be ignored next time.
    		if (url!=null){
   				image = new ImageIcon(url);
    			panel.setMolImage(image);
    		}
    		saveCache();
		}
    	
    }
    
    
	public static void populateImagePanel(StoiPanel panel,Molecule molecule){
    	String name = molecule.toString();
    	ImageIcon image = null;
    	if (images.containsKey(name)){
    		image = images.get(name);
    		if (image!=null)
    			panel.setMolImage(image);
    	}else{
    		Runnable runnable = new LookupWorker(panel,molecule);
    		Thread worker = new Thread(runnable);
    		worker.start();
    	}  	
    }
	
    
    private static URL lookupImageURL(Molecule molecule) {
    	//TODO It would be best (in the future) to record the elements w/ no image to reduce queries.
    	WAEngine engine = new WAEngine();
        String input = molecule.toString();

        // These properties will be set in all the WAQuery objects created from this WAEngine.
        engine.setAppID(appid);
        engine.addFormat("image");
        // Create the query.
        WAQuery query = engine.createQuery();
        // Set properties of the query.
        query.setInput(input);
        
        //if(molecule.isSingleElement()){
       // 	query.addAssumption("*C."+molecule.getElements().get(0).toString().charAt(0)+"-_*Element-");
       // }
        
        try {
            //print out the URL we are about to send:
            
            // This sends the URL to the Wolfram|Alpha server, gets the XML result
            // and parses it into an object hierarchy held by the WAQueryResult object.
            WAQueryResult queryResult = engine.performQuery(query);
            
            if (queryResult.isError()) {
                System.out.println("Query error");
                System.out.println("  error code: " + queryResult.getErrorCode());
                System.out.println("  error message: " + queryResult.getErrorMessage());
            } else if (!queryResult.isSuccess()) {
                System.out.println("Query was not understood; no results available.");
            } else {
                // Got a result.
                for (WAPod pod : queryResult.getPods()) {
                    if (pod.getTitle().equals("3D structure")) {//||pod.getTitle().equals("Periodic table location")
                        for (WASubpod subpod : pod.getSubpods()) {
                            for (Object element : subpod.getContents()) {
                               WAImage image = (com.wolfram.alpha.WAImage)element;
                               if(image.getURL()!=null)
                            	   return new URL(image.getURL());
                            }
                        }
                    }
                }
            }
        } catch (WAException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
			System.err.println("Failed to get a valid image url.");
		}
        return null;
    }

}
